/*
Copyright 2011 Raymond Giorgi

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */

package edu.pitt.cs3530.reactors;

import java.io.File;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import edu.pitt.cs3530.controllers.ReactorListener;
import edu.pitt.cs3530.misc.Mutexs;

public class ReactorQos extends ReactorThread {
	private InfoStruct info;
	private double avgQos;

	/**
	 * a class that stores the number made, missed and early requests
	 */
	private class InfoStruct {
		int made;
		int missed;
		int madeInLowerDeadline;

		private InfoStruct() {
			made = 0;
			missed = 0;
			madeInLowerDeadline = 0;
		}
	}

	public ReactorQos(long deadline, long lowerDeadline, long sleepTime,
			long oldTime, String qosName, Map<String, String> parameterMap) {
		super(deadline, lowerDeadline, sleepTime, oldTime, qosName, parameterMap);
		info = new InfoStruct();
	}

	@Override
	protected void generateResults() {
		double currentTime = (new Date()).getTime() + 1000.0;
		File file = new File(directory);
		int tempMissed = 0;
		int tempMade = 0;
		int tempMadeInLowerDeadline = 0;
		File files[] = file.listFiles();
		StringTokenizer tok = null;
		// int madeInBound = 0;
		Mutexs.lockFileMutex();
		List<Double> time = new LinkedList<Double>();
		double totalQos = 0.0;
		for (File f : files) {
			if (f.getName().startsWith("fin")) {
				tok = new StringTokenizer(f.getName(), "-");
				tok.nextToken();
				double firstSec = Double.parseDouble(tok.nextToken());
				double firstUsec = Double.parseDouble(tok.nextToken());
				if ((firstSec * 1000000 + firstUsec) / 1000 > currentTime
						- oldTime) {
					double secondSec = Double.parseDouble(tok.nextToken());
					double secondUsec = Double.parseDouble(tok.nextToken());
					double fin = ((secondSec - firstSec) * 1000000.0 + (secondUsec - firstUsec)) / 1000.0;
					// System.out.println(deadline + ":::" + fin + ":::" +
					// this.lowerDeadline);
					time.add(fin);
					totalQos += fin / deadline;
					if (deadline >= fin) {
						tempMade++;
						if (deadline - fin <= this.lowerDeadline) {
							tempMadeInLowerDeadline++;
						}
					} else {
						tempMissed++;
					}
				}
			}
		}
		this.avgQos = totalQos / time.size();
		synchronized (info) {
			this.setMade(tempMade, tempMissed, tempMadeInLowerDeadline);
		}
		this.setMade(tempMade, tempMissed);
		Mutexs.unlockFileMutex();
	}

	public void setMade(int tempMade, int tempMissed,
			int tempMadeInLowerDeadline) {
		this.info.made = tempMade;
		this.info.missed = tempMissed;
		this.info.madeInLowerDeadline = tempMadeInLowerDeadline;
	}

	@Override
	public int getMade() {
		return info.made;
	}

	@Override
	public int getMissed() {
		return info.missed;
	}

	@Override
	public int getTotal() {
		return info.made + info.missed;
	}

	@Override
	public int getMadeInLowerDeadline() {
		return info.madeInLowerDeadline;
	}

	@Override
	public double getPercentMissed() {
		return (double) info.missed / (double) (info.made + info.missed);
	}

	@Override
	public double getPercentMade() {
		return (double) info.made / (double) (info.made + info.missed);
	}

	@Override
	public double getPercentMadeInLowerDeadline() {
		return (double) info.madeInLowerDeadline
				/ (double) (info.made + info.missed);
	}

	public double getQos() {
		return this.avgQos;
	}

	protected void alertListeners() {
		synchronized (info) {
			for (ReactorListener rl : listeners) {
				rl.alertResponseListener(this);
			}
		}
	}
}
